package controllers;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.google.gson.*;
import constants.ErrorTplPath;
import constants.ws.ResultBean;
import duppentity.*;
import play.Logger;
import play.Play;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Scope;
import play.mvc.results.RenderJson;
import play.mvc.results.RenderText;
import org.apache.commons.lang.StringUtils;
import protocol.JsonHandler;
import protocol.JsonRequest;
import protocol.JsonResponse;

import java.lang.reflect.Field;
import java.util.*;

/**
 * Controller基类
 * @author zhangzc@djcars.cn
 */
public class BaseController extends Controller {


    /**
     * 加载失败页面
     */
    protected static void failed(){
        renderTemplate(ErrorTplPath.LOAD_FAIL);
    }

    /**
     * 如果对象为空,则显示加载失败
     * @param condition
     */
    protected static void failedIfNull(Object condition){
        if(condition == null){
            failed();
        }
    }

    /**
     * 如果条件不成立,则显示加载失败
     * @param condition
     */
    protected static void failedIfFalse(boolean condition){
        if(!condition){
            failed();
        }
    }

    /**
     * 对基础类型进行处理
     * @param e
     * @return
     */
    private static JsonElement processJsonPrimitive(JsonElement e){
        if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isNumber()){ //GSON对Long的序列化,会产生一定漂移,导致Long类型的ID出错,所以转换成字符串
            if(e.getAsJsonPrimitive().isNumber()){
                JsonPrimitive number = new JsonPrimitive(new String(e.toString()));
                return number;
            }
        }
        return e;
    }

    /**
     * 递归过滤
     * @param e
     * @param prefix
     * @param whiteSet
     */
    private static JsonElement filterJsonElement(JsonElement e, String prefix, Set<String> whiteSet){
        if(e.isJsonObject()){
            JsonObject object = e.getAsJsonObject();
            for(Map.Entry<String, JsonElement> eM: object.entrySet()){
                String key = eM.getKey();
                JsonElement subE = eM.getValue();
                String filterKey = (StringUtils.isEmpty(prefix) ? "" : (prefix + ".")) + key;

                if(whiteSet.contains(filterKey)){
                    if(subE.isJsonObject() || subE.isJsonArray()){
                        JsonElement newE = filterJsonElement(subE, filterKey, whiteSet);
                        object.add(key, newE);
                    }else{
                        object.add(key, processJsonPrimitive(subE));
                    }
                }else{
                    object.remove(eM.getKey());
                }
            }
            return e;
        }else if(e.isJsonArray()){
            JsonArray resultArray = new JsonArray();
            JsonArray srcArray = e.getAsJsonArray();
            for(JsonElement eArr: srcArray){
                if(eArr.isJsonPrimitive() || eArr.isJsonNull()){
                    resultArray.add(processJsonPrimitive(eArr));
                }else if(eArr.isJsonObject()){
                    JsonElement newE = filterJsonElement(eArr, prefix, whiteSet);
                    resultArray.add(newE);
                }

            }
            return resultArray;
        }else{
            return processJsonPrimitive(e);
        }

    }

    /**
     * 渲染json, 调用者需要提供字段白名单
     * @param e JsonObject/JsonArray
     * @param whiteList 字段白名单,不填表示全部输出
     */
    protected static void renderJSONElement(JsonElement e, String... whiteList){
        if(Play.mode.isDev()){ //方便调试
            if(whiteList != null && whiteList.length > 0){
                Logger.info("renderJSONElement WhiteList: %s", StringUtils.join(whiteList, ","));
            }
            Logger.info("renderJSONElement Source: %s", new GsonBuilder().create().toJson(e));
        }
        if(whiteList == null || whiteList.length == 0){//全字段输出
            String json = new GsonBuilder().setLongSerializationPolicy(LongSerializationPolicy.STRING).create().toJson(e);
            throw new RenderJson(json);
        }
        final Set<String> whiteSet = new HashSet();
        for(String w: whiteList){
            if(StringUtils.contains(w, '.')){
                /**
                 * 如果提供了白名单 x.y.z, 那么白名单列表里面应该放入:
                 * x
                 * x.y
                 * x.y.z
                 */
                String[] parts = StringUtils.split(w, '.');
                StringBuilder white = new StringBuilder();
                for(String p: parts){
                    if(StringUtils.isNotEmpty(p)){ //排除无效字符串
                        white.append(p);
                        whiteSet.add(white.toString());
                        //准备下次拼接
                        white.append('.');
                    }
                }
            }else{
                whiteSet.add(w);
            }

        }

        JsonElement result = filterJsonElement(e, StringUtils.EMPTY, whiteSet);

        String json = new GsonBuilder().setLongSerializationPolicy(LongSerializationPolicy.STRING).create().toJson(result);
        throw new RenderJson(json);

    }

    protected static void wsOk(){
        ResultBean result = new ResultBean(0, "OK");
        renderXJSON(result);
    }

    protected static void wsOk(Object data){
        if(data instanceof JsonObject){
            data = JSON.parseObject(((JsonObject)data).toString());
        }
        if(data instanceof List){
            List list = (List) data;
            Map<String, Object> r = new HashMap();
            r.put("total", list.size());
            r.put("list", list);
            data = r;
        }
        ResultBean result = new ResultBean(0, data);
        renderXJSON(result);
    }

    protected static void wsError(String message){
        ResultBean result = new ResultBean(1, message);
        renderXJSON(result);
    }

    static void renderXJSON(Object obj){
        response.setContentTypeIfNotSet("application/json; charset=utf-8");
        String jsonString = JSON.toJSONString(obj, new ValueFilter() {
            @Override
            public Object process(Object o, String propertyName, Object propertyValue){
                if(org.apache.commons.lang3.StringUtils.endsWith(propertyName, "Id") || org.apache.commons.lang3.StringUtils.equals(propertyName, "id")){
                    if(propertyValue != null){
                        return propertyValue.toString();
                    }
                }
                return propertyValue;

            }
        });
        throw new RenderText(jsonString);
    }

    /**
     * 用于记录请求对象的key
     */
    private static final String PARAM_JSON_KEY = "requestJSON";

    /**
     * 返回请求对象，如果未解析则解析后再返回
     *
     * @return
     */
    protected static JsonRequest getRequest() {

        Object json = request.args.get(PARAM_JSON_KEY);
        if (json == null) {
            try {
                request.body.reset();
                json = JsonHandler.parseRequestBody(request.body);
            } catch (Exception e) {
                Logger.error("解析json格式出错", e);
                // 此时request未能解析成功，不能直接调用jsonXXX方法，可能导致死循环
                // 直接写出响应
            }
            if (json == null) {
                json = new JsonRequest();
            }
            request.args.put(PARAM_JSON_KEY, json);
        }
        return (JsonRequest) json;
    }
}
